﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace IBNet.UtilsDataStructuresAndExtensions
{
   /// <summary>
   /// An alarm clock that calls a specified TimerCallback at a specified time of day.
   /// </summary>
   public class AlarmClock : IDisposable
   {
      private readonly System.Threading.Timer _alarm;

      /// <summary>
      /// Creates a new AlarmClock which calls a specified TimerCallback at a specified time.
      /// The alarm will only be set if the time specified is in the future.
      /// </summary>
      /// <param name="hour">The alarm hour.</param>
      /// <param name="minute">The alarm minute.</param>
      /// <param name="second">The alarm second.</param>
      /// <param name="callback">The TimerCallback to call when the alarm time is reached.</param>
      public AlarmClock(int hour, int minute, int second, TimerCallback callback)
      {
         if (callback == null)
            throw new ArgumentNullException("callback");
         if (hour < 0 || hour >= 24)
            throw new ArgumentException("hour must be >= 0 and < 24");
         if (minute < 0 || minute >= 60)
            throw new ArgumentException("minute must be >= 0 and < 60");
         if (second < 0 || second >= 60)
            throw new ArgumentException("minute must be >= 0 and < 60");

         TimeSpan dueTime = new TimeSpan(hour, minute, second);
         int dueTimeMilliseconds = (int)(dueTime - DateTime.Now.TimeOfDay).TotalMilliseconds;

         if (dueTimeMilliseconds >= 0)
         {
            _alarm = new System.Threading.Timer(callback, null, dueTimeMilliseconds, -1);
         }
      }

      /// <summary>
      /// Releases resources used by the AlarmClock.
      /// </summary>
      public void Dispose()
      {
         Dispose(true);
         GC.SuppressFinalize(this);
      }

      protected virtual void Dispose(bool disposing)
      {
         _alarm.Dispose();
      }
   }
}
